package org.springside.modules.web.struts2;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.MethodUtils;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;

/**
 * CRUD的Action基类. 用户项目中的CRUD方法可能会有不同,可进行扩展或重新编写CRUDAction和CRUDInvoker.
 * 
 * @param <T>
 *            CRUD对象的类型
 * 
 * @see Preparable
 * @see ModelDriven
 * 
 * @author calvin
 */
@SuppressWarnings("unchecked")
public abstract class CRUDAction<T> extends ActionSupport implements Preparable, ModelDriven
{

	// list页面定义
	public static final String LIST = "list";

	// logger for subclass
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	// the model
	protected T entity;

	protected String msg;

	protected int pageIndex = 1;

	protected int pageSize = 1;

	protected int pagePrev;

	protected int pageNext;

	protected Long pageCount;

	protected int objectCount;

	protected String queryCondition = "";

	protected String queryString;

	protected Map<String, String> params = new HashMap();
	// model's Class
	protected Class<T> entityClass;

	// model's ClassName
	protected String entityClassName;

	// manager's CRUD method invoker
	protected CRUDInvoker invoker;

	// list页面显示的对象列表
	protected List<T> entites;

	public CRUDAction()
	{
		super();
		// 通过反射取得Entity的Class.
		this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		entityClassName = entityClass.getSimpleName();
	}

	/**
	 * @see ModelDriven
	 */
	public T getModel()
	{
		return entity;
	}

	/**
	 * @see Preparable
	 */
	public void prepare() throws Exception
	{
		if (getId() != null)
		{
			entity = (T) MethodUtils.invokeMethod(getManager(), "get" + entityClassName, getId());
			if (entity == null)
				throw new IllegalArgumentException("id not exist");
		} else
			entity = entityClass.newInstance();
		onPrepare();
	}

	/**
	 * 显示对象列表页.
	 */
	public String list() throws Exception
	{
		onDisplayPrepare();
		// 符合条件总条数
		if (pageSize != 0)
		{
			objectCount = new Long(getInvoker().getCount(getManager(), entityClassName, params)).intValue();
			pageCount = new Long(objectCount / pageSize);
			if ((objectCount % pageSize) > 0)
				pageCount++;
			if (pageIndex > pageCount)
				pageIndex = pageCount.intValue();
			if (pageIndex > 1)
				pagePrev = pageIndex - 1;
			if (pageIndex < pageCount)
				pageNext = pageIndex + 1;
		}
		entites = getInvoker().getAllByPropertysWith(getManager(), entityClassName, params, new int[]
		{ pageIndex - 1, pageSize });
		return LIST;
	}

	/**
	 * 显示新增或修改的表单.
	 */
	@Override
	public String input() throws Exception
	{
		onInputPrepare();
		return INPUT;
	}

	/**
	 * 新增或修改对象保存.
	 */
	public String save() throws Exception
	{
		onSavePrepare();
		if (getId() == null)
			getInvoker().create(getManager(), entityClass, entity);
		else
			getInvoker().update(getManager(), entityClass, entity);
		return SUCCESS;
	}

	/**
	 * 删除对象.
	 */
	public String delete() throws Exception
	{
		getInvoker().delete(getManager(), entityClassName, getId());
		return SUCCESS;
	}

	/**
	 * 默认执行函数,显示对象列表.
	 */
	@Override
	public String execute() throws Exception
	{
		return list();
	}

	/**
	 * 向显示页面返回对象列表.
	 */
	public List<T> getEntites()
	{
		return entites;
	}

	/**
	 * 取得Manager的CRUD方法反射调用者. 用户可重载此方法注入自己的Invoker.
	 */
	protected CRUDInvoker getInvoker()
	{
		if (invoker == null)
			invoker = new DefaultCRUDInvoker();
		return invoker;
	}

	/**
	 * 取得管理Manager,子类必须实现.
	 */
	protected abstract Object getManager();

	/**
	 * 从参数中取得id,子类必须实现.
	 */
	protected abstract Object getId();

	/**
	 * @see #prepare()
	 */
	protected void onPrepare()
	{
		// empty,可在子类重载,在prepare()中调用.
	}

	/**
	 * @see #list()
	 * @see #input()
	 */
	protected void onDisplayPrepare()
	{
		// empty,可在子类重载.准备显示页面需要的辅助对象,在list()、input()中调用.
	}

	protected void onSavePrepare()
	{

	}

	protected void onInputPrepare()
	{

	}

	/**
	 * Convenience method to get the request
	 * 
	 * @return current request
	 */
	public HttpServletRequest getRequest()
	{
		return ServletActionContext.getRequest();
	}

	public HttpServletResponse getResponse()
	{
		return ServletActionContext.getResponse();
	}

	/**
	 * Convenience method to get the session
	 */
	public HttpSession getSession()
	{
		return getRequest().getSession();
	}

	// 异常信息
	public String getMsg()
	{
		return msg;
	}

	public void setMsg(String msg)
	{
		this.msg = msg;
	}

	public int getPageIndex()
	{
		return pageIndex;
	}

	public void setPageIndex(int pageIndex)
	{
		this.pageIndex = pageIndex;
	}

	public Long getPageCount()
	{
		return pageCount;
	}

	public void setPageCount(Long pageCount)
	{
		this.pageCount = pageCount;
	}

	public int getPageSize()
	{
		return pageSize;
	}

	public void setPageSize(int pageSize)
	{
		this.pageSize = pageSize;
	}

	public int getPagePrev()
	{
		return pagePrev;
	}

	public void setPagePrev(int pagePrev)
	{
		this.pagePrev = pagePrev;
	}

	public int getPageNext()
	{
		return pageNext;
	}

	public void setPageNext(int pageNext)
	{
		this.pageNext = pageNext;
	}

	public int getObjectCount()
	{
		return objectCount;
	}

	public void setObjectCount(int objectCount)
	{
		this.objectCount = objectCount;
	}

	public String getQueryCondition()
	{
		return queryCondition;
	}

	public void setQueryCondition(String queryCondition)
	{
		this.queryCondition = queryCondition;
	}

}
